/*-------------------------------------------------------------------------
 *
 * fe_memutils.c
 *	  前端代码的内存管理支持
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/common/fe_memutils.c
 *
 *-------------------------------------------------------------------------
 */

#ifndef FRONTEND
#error "This file is not expected to be compiled for backend code"
#endif

#include "postgres_fe.h"

static inline void *
fc_pg_malloc_internal(size_t fc_size, int fc_flags)
{
	void	   *fc_tmp;

	/* 避免 malloc(0) 的不可移植行为 */
	if (fc_size == 0)
		fc_size = 1;
	fc_tmp = malloc(fc_size);
	if (fc_tmp == NULL)
	{
		if ((fc_flags & MCXT_ALLOC_NO_OOM) == 0)
		{
			fprintf(stderr, _("out of memory\n"));
			exit(EXIT_FAILURE);
		}
		return NULL;
	}

	if ((fc_flags & MCXT_ALLOC_ZERO) != 0)
		MemSet(fc_tmp, 0, fc_size);
	return fc_tmp;
}

void * pg_malloc(size_t fc_size)
{
	return fc_pg_malloc_internal(fc_size, 0);
}

void * pg_malloc0(size_t fc_size)
{
	return fc_pg_malloc_internal(fc_size, MCXT_ALLOC_ZERO);
}

void * pg_malloc_extended(size_t fc_size, int fc_flags)
{
	return fc_pg_malloc_internal(fc_size, fc_flags);
}

void * pg_realloc(void *fc_ptr, size_t fc_size)
{
	void	   *fc_tmp;

	/* 避免 realloc(NULL, 0) 的不可移植行为 */
	if (fc_ptr == NULL && fc_size == 0)
		fc_size = 1;
	fc_tmp = realloc(fc_ptr, fc_size);
	if (!fc_tmp)
	{
		fprintf(stderr, _("out of memory\n"));
		exit(EXIT_FAILURE);
	}
	return fc_tmp;
}

/*
 * "安全" 的 strdup() 包装器。
 */
char * pg_strdup(const char *fc_in)
{
	char	   *fc_tmp;

	if (!fc_in)
	{
		fprintf(stderr,
				_("cannot duplicate null pointer (internal error)\n"));
		exit(EXIT_FAILURE);
	}
	fc_tmp = strdup(fc_in);
	if (!fc_tmp)
	{
		fprintf(stderr, _("out of memory\n"));
		exit(EXIT_FAILURE);
	}
	return fc_tmp;
}

void pg_free(void *fc_ptr)
{
	if (fc_ptr != NULL)
		free(fc_ptr);
}

/*
 * 后端内存管理函数的前端仿真。 对于编译后端文件的程序很有用。
 */
void * palloc(Size fc_size)
{
	return fc_pg_malloc_internal(fc_size, 0);
}

void * palloc0(Size fc_size)
{
	return fc_pg_malloc_internal(fc_size, MCXT_ALLOC_ZERO);
}

void * palloc_extended(Size fc_size, int fc_flags)
{
	return fc_pg_malloc_internal(fc_size, fc_flags);
}

void pfree(void *fc_pointer)
{
	pg_free(fc_pointer);
}

char * pstrdup(const char *fc_in)
{
	return pg_strdup(fc_in);
}

char * pnstrdup(const char *fc_in, Size fc_size)
{
	char	   *fc_tmp;
	int			fc_len;

	if (!fc_in)
	{
		fprintf(stderr,
				_("cannot duplicate null pointer (internal error)\n"));
		exit(EXIT_FAILURE);
	}

	fc_len = strnlen(fc_in, fc_size);
	fc_tmp = malloc(fc_len + 1);
	if (fc_tmp == NULL)
	{
		fprintf(stderr, _("out of memory\n"));
		exit(EXIT_FAILURE);
	}

	memcpy(fc_tmp, fc_in, fc_len);
	fc_tmp[fc_len] = '\0';

	return fc_tmp;
}

void * repalloc(void *fc_pointer, Size fc_size)
{
	return pg_realloc(fc_pointer, fc_size);
}
